package com.flycms.modules.picture.service.impl;

import com.flycms.common.constant.SiteConstants;
import com.flycms.common.utils.FileUtils;
import com.flycms.common.utils.StringUtils;
import com.flycms.common.utils.mark.SnowFlakeUtils;
import com.flycms.modules.picture.dao.PictureDao;
import com.flycms.modules.picture.entity.Picture;
import com.flycms.modules.picture.entity.PictureCompany;
import com.flycms.modules.picture.entity.PictureInfo;
import com.flycms.modules.picture.service.PictureService;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.imageio.ImageIO;
import java.awt.image.BufferedImage;
import java.io.*;
import java.net.HttpURLConnection;
import java.net.URL;
import java.security.MessageDigest;
import java.time.LocalDateTime;
import java.util.Calendar;
import java.util.Date;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

/**
 * Biz-Boot, All rights reserved
 * 版权：企业之家网 -- 企业建站管理系统<br/>
 * 开发公司：97560.com<br/>
 *
 * @author 孙开飞
 * @version 1.0 <br/>
 * @Description: 图片存储服务
 * @email 79678111@qq.com
 * @Date: 20:09 2019/11/4
 */
@Service
public class PictureServiceImpl implements PictureService {
    private static final Logger log = LoggerFactory.getLogger(PictureServiceImpl.class);
    @Autowired
    protected SiteConstants siteConstants;
    @Autowired
    private PictureDao pictureDao;

    // ///////////////////////////////
    // /////       增加       ////////
    // ///////////////////////////////

    /**
     * 添加图片信息
     *
     * @param picture
     * @return
     * @throws Exception
     */
    @Transactional
    public boolean addUserPicture(Picture picture) throws Exception{
        File file = new File(siteConstants.getUploadLoaderPath() +picture.getImgUrl());
        FileInputStream fis = new FileInputStream(file);
        BufferedImage sourceImg = ImageIO.read(fis);
        picture.setId(SnowFlakeUtils.nextId());
        picture.setFileSize(String.format("%.1f", file.length() / 1024.0));
        picture.setImgWidth(Integer.toString(sourceImg.getWidth()));
        picture.setImgHeight(Integer.toString(sourceImg.getHeight()));
        picture.setCreateTime(LocalDateTime.now());
        int totalCount=pictureDao.save(picture);
        if(totalCount > 0){
            PictureCompany merge = new PictureCompany();
            merge.setId(SnowFlakeUtils.nextId());
            merge.setCompanyId(picture.getCompanyId());
            merge.setPictureId(picture.getId());
            pictureDao.savePictureCompany(merge);
        }else{
            return false;
        }
        fis.close();
        return true;
    }

    /**
     *
     *
     * @param info
     * @return
     */
    @Transactional
    public Object savePictureInfo(PictureInfo info){
        info.setId(SnowFlakeUtils.nextId());
        return pictureDao.savePictureInfo(info);
    }

    /**
     * 更新内容时对已有的图片数据分析本地化路径处理
     *
     * @param content
     *         需要分析的内容
     * @param companyId
     *         企业id
     * @param typeId
     *         图片类型
     * @param infoId
     *         信息id
     * @return
     * @throws Exception
     */
    public String replaceContent(String content, Long companyId, Integer typeId, Long infoId){
        try {
            String sitedirect = siteConstants.getUploadLoaderPath();
            Pattern pRemoteFileurl = Pattern.compile("<img.*?src=\"?(.*?)(\"|>|\\s+)");
            Matcher mRemoteFileurl = pRemoteFileurl.matcher(content);
            StringBuffer sb = new StringBuffer();
            String remoteFileurl = null;
            //创建文件夹并返回根目录，如：“/upload/content/2018/8/20/4CAF5F732B9E4523_0.jpg”
            String imgpath = getImgPath();
            StringBuffer imgPath = new StringBuffer();
            String pathac ="";
            while (mRemoteFileurl.find()) {
                remoteFileurl = mRemoteFileurl.group(1);
                //图片指纹MD5为文件名
                String fileName = null;
                String reg = "(?!.*((127.0.0.1)|(^/upload/))).*$";
                if (remoteFileurl.matches(reg)) {
                    URL url = new URL(remoteFileurl);
                    HttpURLConnection connection = (HttpURLConnection) url.openConnection();
                    InputStream is = connection.getInputStream();
                    String type=connection.getContentType();

                    //图片指纹MD5为文件名
                    fileName = this.md5HashCode32(is);
                    String extension = FileUtils.getFileType(type);
                    Picture picture=this.findPictureBySignature(companyId,fileName);
                    if(picture!=null){
                        mRemoteFileurl.appendReplacement(sb, "<img src=\"" + picture.getImgUrl()+"\" ");
                        if (imgPath.toString().length() < 1) {
                            imgPath.append(picture.getImgUrl());
                        } else {
                            imgPath.append(";").append(picture.getImgUrl());
                        }
                        if(!this.checkPictureByInfoId(picture.getId(),infoId)){
                            PictureInfo info= new PictureInfo();
                            info.setTypeId(typeId);
                            info.setPictureId(picture.getId());
                            info.setInfoId(infoId);
                            this.savePictureInfo(info);
                        }
                        int total=pictureDao.queryPictureByInfoTotal(companyId,fileName);
                        pictureDao.updatePictureInfoCount(total,picture.getId());
                    }else{
                        saveNetworkPicture(remoteFileurl, sitedirect + imgpath + fileName + extension);
                        pathac = imgpath + fileName + extension;
                        mRemoteFileurl.appendReplacement(sb, "<img src=\"" + pathac+"\" ");
                        if (imgPath.toString().length() < 1) {
                            imgPath.append(pathac);
                        } else {
                            imgPath.append(";").append(pathac);
                        }
                        //图片信息写入数据库
                        Picture img = new Picture();
                        img.setSignature(fileName);
                        img.setImgUrl(pathac);
                        img.setCompanyId(companyId);
                        img.setImgName(fileName + extension);
                        this.addUserPicture(img);
                    }
                } else {
                    Picture picture=this.findPictureBySignature(companyId,StringUtils.getFileName(remoteFileurl));
                    if(picture!=null){
                        if(!this.checkPictureByInfoId(picture.getId(),infoId)){
                            PictureInfo info= new PictureInfo();
                            info.setTypeId(typeId);
                            info.setPictureId(picture.getId());
                            info.setInfoId(infoId);
                            this.savePictureInfo(info);
                        }
                        int total=pictureDao.queryPictureByInfoTotal(companyId,fileName);
                        pictureDao.updatePictureInfoCount(total,picture.getId());
                    }
                }
            }
            mRemoteFileurl.appendTail(sb);
            return sb.toString();
        } catch (Exception e) {
            log.error(e.getMessage());
        }
        return null;
    }

    /**
     * @param networUrl
     *            文件来源地址
     * @param savePath
     *            文件保存地址
     * @return
     */
    public static boolean saveNetworkPicture(String networUrl, String savePath) {
        try {
            URL url = new URL(networUrl);
            HttpURLConnection connection = (HttpURLConnection) url.openConnection();
            DataInputStream in = new DataInputStream(connection.getInputStream());
            DataOutputStream out = new DataOutputStream(new FileOutputStream(savePath));
            byte[] buffer = new byte[4096];
            int count = 0;
            while ((count = in.read(buffer)) > 0) {
                out.write(buffer, 0, count);
            }
            out.close();
            in.close();
            connection.disconnect();
            return true;

        } catch (Exception e) {
            return false;
        }
    }

    /*
     *
     * 内容下载图片保存路径设置
     */
    public String getImgPath() {
        String path = siteConstants.getUploadLoaderPath(),
                filepath= "/upload/" + Calendar.getInstance().get(Calendar.YEAR)
                        + "/" + (1 + Calendar.getInstance().get(Calendar.MONTH)) + "/"
                        + (Calendar.getInstance().get(Calendar.DATE)) + "/";

        File file = new File(path+filepath);
        // 如果文件夹不存在则创建
        if (!file.exists() && !file.isDirectory()) {
            file.mkdirs();
        }
        return filepath;
    }
    // ///////////////////////////////
    // /////        刪除      ////////
    // ///////////////////////////////
    /**
     * 按id删除图片主表信息
     *
     * @param id
     * @return
     */
    public int deleteById(Long id){
        return pictureDao.deleteById(id);
    }
    // ///////////////////////////////
    // /////        修改      ////////
    // ///////////////////////////////
    /**
     * 更新统计当前图片使用数量
     *
     * @param countInfo
     * @param id
     * @return
     */
    public int updatePictureInfoCount(Integer countInfo,Long id){
        return pictureDao.updatePictureInfoCount(countInfo,id);
    }


    // ///////////////////////////////
    // /////        查詢      ////////
    // ///////////////////////////////
    /**
     * 按企业id和图片唯一指纹查询是否存在
     *
     * @param companyId
     * @param signature
     * @return
     */
    public boolean checkPictureBySignature(Long companyId,String signature) {
        int totalCount = pictureDao.checkPictureBySignature(companyId,signature);
        return totalCount > 0 ? true : false;
    }

    /**
     * 按信息id和图片id查询是否存在
     *
     * @param pictureId
     *         图片id
     * @param infoId
     *         信息id
     * @return
     */
    public boolean checkPictureByInfoId(Long pictureId,Long infoId) {
        int totalCount = pictureDao.checkPictureByInfoId(pictureId,infoId);
        return totalCount > 0 ? true : false;
    }

    /**
     * 按id查询图片内容
     *
     * @param id
     * @return
     */
    public Picture findById(Long id){
        return pictureDao.findById(id);
    }

    /**
     * 按图片指纹和企业id查询图片被使用的数量
     *
     * @param companyId
     * @param signature
     * @return
     */
    public int queryPictureByInfoTotal(Long companyId,String signature){
        return pictureDao.queryPictureByInfoTotal(companyId,signature);
    }

    /**
     * 按企业id和图片唯一指纹查询图片信息
     *
     * @param companyId
     * @param signature
     * @return
     */
    public Picture findPictureBySignature(Long companyId,String signature){
        return pictureDao.findPictureBySignature(companyId,signature);
    }

    /**
     * java计算文件32位md5值,生成图片指纹用户排除重复内容
     * @param fis 输入流
     * @return
     */
    public String md5HashCode32(InputStream fis) {
        try {
            //拿到一个MD5转换器,如果想使用SHA-1或SHA-256，则传入SHA-1,SHA-256
            MessageDigest md = MessageDigest.getInstance("MD5");

            //分多次将一个文件读入，对于大型文件而言，比较推荐这种方式，占用内存比较少。
            byte[] buffer = new byte[1024];
            int length = -1;
            while ((length = fis.read(buffer, 0, 1024)) != -1) {
                md.update(buffer, 0, length);
            }
            fis.close();

            //转换并返回包含16个元素字节数组,返回数值范围为-128到127
            byte[] md5Bytes  = md.digest();
            StringBuffer hexValue = new StringBuffer();
            for (int i = 0; i < md5Bytes.length; i++) {
                int val = ((int) md5Bytes[i]) & 0xff;//解释参见最下方
                if (val < 16) {
                    /**
                     * 如果小于16，那么val值的16进制形式必然为一位，
                     * 因为十进制0,1...9,10,11,12,13,14,15 对应的 16进制为 0,1...9,a,b,c,d,e,f;
                     * 此处高位补0。
                     */
                    hexValue.append("0");
                }
                //这里借助了Integer类的方法实现16进制的转换
                hexValue.append(Integer.toHexString(val));
            }
            return hexValue.toString();
        } catch (Exception e) {
            e.printStackTrace();
            return "";
        }
    }
}
